package com.demarc.pesquisas.negocio.service;

import java.io.Serializable;
import java.util.List;

import org.springframework.transaction.annotation.Transactional;

import com.demarc.pesquisas.infraestrutura.excecao.NegocioException;
import com.demarc.pesquisas.infraestrutura.excecao.NegocioExceptionUtil;
import com.demarc.pesquisas.infraestrutura.persistencia.Filtro;
import com.demarc.pesquisas.infraestrutura.persistencia.ObjetoPersistenteVersionado;
import com.demarc.pesquisas.infraestrutura.persistencia.ResultadoPaginado;
import com.demarc.pesquisas.infraestrutura.util.utils.DemarPesquisasUtil;
import com.demarc.pesquisas.negocio.dao.AbstractDAO;

public abstract class AbstractService<T extends ObjetoPersistenteVersionado<ID>, ID extends Serializable>
		implements IService<T, ID> {

	public abstract AbstractDAO<T, ID> getDAO();

	/** {@inheritDoc} */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void salvar(T entidade) {
		validarEntidade(entidade);
		validarInclusao(entidade);
		try {
			getDAO().salvar(entidade);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/** {@inheritDoc} */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void alterar(T entidade) {
		validarEntidade(entidade);
		validarAlteracao(entidade);
		try {
			getDAO().alterar(entidade);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/** {@inheritDoc} */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void salvarOuAlterar(T entidade) {
		validarEntidade(entidade);
		validarInclusaoOuAlteracao(entidade);
		try {
			getDAO().salvarOuAlterar(entidade);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/** {@inheritDoc} */
	@Override
	public void merge(T entidade) {
		validarEntidade(entidade);
		validarAlteracao(entidade);
		try {
			getDAO().merge(entidade);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/** {@inheritDoc} */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void excluir(T entidade) {
		validarExclusao(entidade);
		try {
			getDAO().excluir(entidade);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/** {@inheritDoc} */
	@Override
	@Transactional(readOnly = true)
	public T buscarPor(ID id) {
		try {
			return getDAO().buscarPor(id);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/** {@inheritDoc} */
	@Override
	public <E> E buscarMaiorValor(String property, Filtro filtro) {
		return getDAO().buscarMaiorPor(property, filtro);
	}

	/** {@inheritDoc} */
	@Override
	@Transactional(readOnly = true)
	public List<T> consultarPorCampo(String nomeCampo, Object valorCampo,
			String... atributosEOrdem) {
		return getDAO().consultarPorCampo(nomeCampo, valorCampo,
				atributosEOrdem);
	}

	/** {@inheritDoc} */
	@Override
	@Transactional(readOnly = true)
	public ResultadoPaginado<T> consultarPaginandoPorFiltro(Filtro filtro) {
		try {
			return getDAO().consultarPorFiltro(filtro);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/** {@inheritDoc} */
	@Override
	@Transactional(readOnly = true)
	public <E> List<E> listarPor(String property) {
		return getDAO().listarPor(property);
	}

	/** {@inheritDoc} */
	@Override
	@Transactional(readOnly = true)
	public List<T> listarOrdenadoPor(String... atributosEOrdem) {
		return getDAO().listarOrdenadoPor(atributosEOrdem);
	}

	/** {@inheritDoc} */
	private void validarEntidade(T entidade) {
		NegocioExceptionUtil.lancarExcecao(entidade.validar());
	}

	/** {@inheritDoc} */
	@Override
	@Transactional(readOnly = true)
	public boolean existe(ID id) {
		try {
			return getDAO().existe(id);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/** {@inheritDoc} */
	@Override
	public final void validarObjetotNuloOuVazio(Object objeto, String msgErro,
			String... parametros) {

		if (DemarPesquisasUtil.isNuloOuVazio(objeto)) {
			throw new NegocioException(msgErro, parametros);
		}
	}

	/** {@inheritDoc} */
	@Override
	public void validarInclusao(T obj) {
		// Implementado na subclasse caso necessário.
	}

	@Override
	public void validarInclusaoOuAlteracao(T obj) {
		// Implementado na subclasse caso necessário.
	}

	/** {@inheritDoc} */
	@Override
	public void validarAlteracao(T obj) {
		// Implementado na subclasse caso necessário.
	}

	/** {@inheritDoc} */
	@Override
	public void validarExclusao(T obj) {
		// Implementado na subclasse caso necessário.
	}
}
